use std::sync::Arc;
use std::fmt::Display;
use parking_lot::Mutex;
use std::collections::HashMap;

use crate::pipeline::*;

pub type Evaluation = Arc<Mutex<EvaluationInner>>;

#[derive(Debug, Clone)]
pub enum DataType {
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    U128(u128),
    F32(f32),
    F64(f64),
    Bool(bool),
    Str(String),
    None,
}

impl Display for DataType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::U8(v) => write!(f, "{}", v),
            Self::U16(v) => write!(f, "{}", v),
            Self::U32(v) => write!(f, "{}", v),
            Self::U64(v) => write!(f, "{}", v),
            Self::U128(v) => write!(f, "{}", v),
            Self::F32(v) => write!(f, "{}", v),
            Self::F64(v) => write!(f, "{}", v),
            Self::Bool(v) => write!(f, "{}", v),
            Self::Str(v) => write!(f, "{}", v),
            Self::None => write!(f,"None"),
        }
    }
}

impl From<u8> for DataType {
    fn from(value: u8) -> Self {
        Self::U8(value)
    }
}

impl From<u16> for DataType {
    fn from(value: u16) -> Self {
        Self::U16(value)
    }
}

impl From<u32> for DataType {
    fn from(value: u32) -> Self {
        Self::U32(value)
    }
}

impl From<u64> for DataType {
    fn from(value: u64) -> Self {
        Self::U64(value)
    }
}

impl From<u128> for DataType {
    fn from(value: u128) -> Self {
        Self::U128(value)
    }
}

impl From<f32> for DataType {
    fn from(value: f32) -> Self {
        Self::F32(value)
    }
}

impl From<f64> for DataType {
    fn from(value: f64) -> Self {
        Self::F64(value)
    }
}

impl From<bool> for DataType {
    fn from(value: bool) -> Self {
        Self::Bool(value)
    }
}

impl From<&str> for DataType {
    fn from(value: &str) -> Self {
        Self::Str(value.to_string())
    }
}

impl From<String> for DataType {
    fn from(value: String) -> Self {
        Self::Str(value)
    }
}

impl TryInto<u8> for DataType {
    type Error = ();
    fn try_into(self) -> Result<u8, Self::Error> {
        if let Self::U8(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<u16> for DataType {
    type Error = ();
    fn try_into(self) -> Result<u16, Self::Error> {
        if let Self::U16(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<u32> for DataType {
    type Error = ();
    fn try_into(self) -> Result<u32, Self::Error> {
        if let Self::U32(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<u64> for DataType {
    type Error = ();
    fn try_into(self) -> Result<u64, Self::Error> {
        if let Self::U64(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<u128> for DataType {
    type Error = ();
    fn try_into(self) -> Result<u128, Self::Error> {
        if let Self::U128(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<f32> for DataType {
    type Error = ();
    fn try_into(self) -> Result<f32, Self::Error> {
        if let Self::F32(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<f64> for DataType {
    type Error = ();
    fn try_into(self) -> Result<f64, Self::Error> {
        if let Self::F64(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<bool> for DataType {
    type Error = ();
    fn try_into(self) -> Result<bool, Self::Error> {
        if let Self::Bool(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

impl TryInto<String> for DataType {
    type Error = ();
    fn try_into(self) -> Result<String, Self::Error> {
        if let Self::Str(value) = self {
            Ok(value)
        } else {
            Err(())
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct EvaluationKey{
    order:usize,
    index:usize,
    key:String,
}

#[derive(Debug, Clone)]
pub struct EvaluationInner {
    name_map:HashMap<String, usize>,
    value_vec:Vec<(EvaluationKey, DataType)>,
}

impl EvaluationInner {
    pub fn new() -> Self {
        Self { name_map:HashMap::new(), value_vec: Vec::new(), }
    }

    pub fn register<O:Into<usize>, S:ToString>(&mut self, order:O, name:S) {
        let order = order.into();
        self.name_map.insert(name.to_string(), self.value_vec.len());
        let key = EvaluationKey { order, index:self.value_vec.len(), key:name.to_string() };
        self.value_vec.push((key, DataType::None));
    }

    pub fn get<S:ToString>(&mut self, name:S) -> Option<DataType> {
        let entry_index = *self.name_map.get(&name.to_string())?;
        self.value_vec.get(entry_index).map(|e|e.1.clone())
    }

    pub fn set<S, V>(&mut self, name:S, value:V) 
        where S:ToString, DataType:From<V>
    {
        let entry_index = *self.name_map.get(&name.to_string()).unwrap();
        self.value_vec[entry_index].1 = DataType::from(value);
    }

    pub fn register_and_set<O:Into<usize>, S, V>(&mut self, order:O, name:S, value:V) 
        where S:ToString, DataType:From<V>
    {
        self.register(order, name.to_string().clone());
        self.set(name, value);
    }

    pub fn display(&self) -> String {
        let mut list:Vec<_> = self.value_vec
            .iter()
            .map(|e|e.0.clone())
            .collect();
        list.sort();
        let mut result = String::new();
        for key in list {
            let str = key.key;
            let value = self.value_vec[key.index].1.clone();
            result.push_str(format!("{}: {}\n", str, value).as_str());
        }
        result
    }

    pub fn csv_name_line(&self, line:bool) -> String {
        let mut list:Vec<_> = self.value_vec
            .iter()
            .map(|e|e.0.clone())
            .collect();
        list.sort();
        let mut result = list
            .iter()
            .map(|k|k.key.clone())
            .collect::<Vec<String>>()
            .join(",");
        if line { result.push('\n'); }
        result
    }

    pub fn csv_value_line(&self, line:bool) -> String {
        let mut list:Vec<_> = self.value_vec.clone();
        list.sort_by_key(|e|e.0.clone());
        let mut result = list
            .iter()
            .map(|e|e.1.to_string())
            .collect::<Vec<String>>()
            .join(",");
        if line { result.push('\n'); }
        result
    }
}

pub trait Evaluated:Sized {
    fn register(&self, evaluation:&Evaluation);
    fn eva_wrap(self, evaluation:Evaluation) -> EvaluateWrapper<Self> {
        self.register(&evaluation);
        EvaluateWrapper::raw_merge(self, evaluation)
    }
    fn set_value(&self, evaluation:&Evaluation);
}

pub struct EvaluateWrapper<T:Evaluated> {
    evaluation:Evaluation,
    inner:T,
}

impl<T:Evaluated> EvaluateWrapper<T> {
    pub fn with_evaluation(inner:T, evaluation:Evaluation) -> EvaluateWrapper<T> {
        inner.eva_wrap(evaluation)
    }

    fn raw_merge(inner:T, evaluation:Evaluation) -> EvaluateWrapper<T> {
        Self {
            evaluation,
            inner,
        }
    }
}

impl<T:Evaluated> Drop for EvaluateWrapper<T> {
    fn drop(&mut self) {
        self.inner.set_value(&self.evaluation);
    }
}

impl<I, O, T> MutExecutor<I, O> for EvaluateWrapper<T> 
    where
        I:Send + Sync + 'static,
        O:Send + Sync + 'static,
        T:Evaluated + MutExecutor<I, O>,
{
    type Error = <T as MutExecutor<I, O>>::Error;
    fn exec<'scope, F:FnMut(O)>(&'scope mut self, input:I, output:F) -> Result<(), Self::Error> {
        self.inner.exec(input, output)
    }
}

impl<I, O, T> ImmutExecutor<I, O> for EvaluateWrapper<T> 
    where
        I:Send + Sync + 'static,
        O:Send + Sync + 'static,
        T:Evaluated + ImmutExecutor<I, O>,
{
    type Error = <T as ImmutExecutor<I, O>>::Error;
    fn exec<'scope, F:FnMut(O)>(&'scope self, input:I, output:F) -> Result<(), Self::Error> {
        self.inner.exec(input, output)
    }
}
